
#include "StdAfx.h"
#include "ODBC_DBStatement.h"
#include "ODBC_DBResultSet.h"
#include "ODBC_DBError.h"
#include "DBService.h"

ODBC_DBStatement::ODBC_DBStatement( ODBC_DBSession* session ) : DBStatement( session )
{
	result_set_ = new ODBC_DBResultSet();	
	reset();
}

ODBC_DBStatement::~ODBC_DBStatement(){
	SAFE_DELETE( result_set_ );	
}

int ODBC_DBStatement::executeUpdate(){
	if(! execute( false ) )
		return 1;
	return 0;
}

DBResultSet* ODBC_DBStatement::executeQuery(){
	if(! execute( true ) )
		return 0;
	
	return result_set_;
}

int ODBC_DBStatement::prepare( int result_type ){
	if(! result_set_->makeHandle( session_, result_type ) )		
		return DEFAULT_FAIL;	

	return DEFAULT_SUCCESS;
}

void ODBC_DBStatement::reset(){	
	DBStatement::reset();
	result_set_->reset();

	current_bind_pos_ = 1;	
	cbParm_ = SQL_NTS;	
}

void ODBC_DBStatement::setByte( char& value, short flag ){
	addBindInfo(sizeof(char), flag, (char*)value, SQL_C_TINYINT, SQL_TINYINT);	
}

void ODBC_DBStatement::set2Byte( short& value, short flag ){
	addBindInfo(sizeof(short), flag, (char*)&value, SQL_C_SSHORT, SQL_SMALLINT);
}

void ODBC_DBStatement::set4Byte( int& value, short flag ){
	addBindInfo(sizeof(int), flag, (char*)&value, SQL_C_SLONG, SQL_INTEGER);			
}

void ODBC_DBStatement::set4Byte( unsigned int& value, short flag ){
	addBindInfo(sizeof(size_t), flag, (char*)&value, SQL_C_SLONG, SQL_INTEGER);	
}

void ODBC_DBStatement::set8Byte( __int64& value, short flag ){
	addBindInfo(sizeof(__int64), flag, (char*)&value, SQL_C_SBIGINT, SQL_BIGINT);	
}

void ODBC_DBStatement::setFloat( float& value, short flag ){	
	addBindInfo(sizeof(float), flag, (char*)&value, SQL_C_FLOAT, SQL_FLOAT);	
}

void ODBC_DBStatement::setString( char* value, short flag, int size ){
	if(! size ){
		size = strlen( value );

		if( flag == DEF_PARAM_TYPE_INPUT ){
			value[ 0 ] = ' ';
			size = 1;
		}
	}

	addBindInfo( size, flag, value, SQL_C_CHAR, SQL_CHAR );	
}

void ODBC_DBStatement::setDate( char* value, short flag ){
	int size = strlen( value );

	addBindInfo(size, flag, value, SQL_C_DATE, SQL_DATE);	
}

void ODBC_DBStatement::setMemory( char* value, int size, short flag ){
	addBindInfo( size, flag, value, SQL_C_BINARY, SQL_LONGVARBINARY );
}

void ODBC_DBStatement::setNull(){
}

void ODBC_DBStatement::setReal( double& value, int precision, int scale, short flag ){		
	addBindInfo(sizeof(double), flag, (char*)&value, SQL_C_DOUBLE, SQL_DOUBLE);	
}

int ODBC_DBStatement::execute( bool result ){
#ifndef WIN32
	if( ::SQLPrepare( result_set_->stmt_, (unsigned char*)sql_, SQL_NTS ) != SQL_SUCCESS ){
		session_->set_error( result_set_->stmt_, sql_, (char*)__FUNCTION__, __LINE__ );
		return 0;
	}
#endif

	SQLRETURN retCode = ::SQLExecDirect( result_set_->stmt_, (unsigned char*)sql_, SQL_NTS );

	if( result ){	
		if( ( retCode != SQL_SUCCESS ) && ( retCode != SQL_SUCCESS_WITH_INFO ) ){	
			session_->set_error( result_set_->stmt_, sql_, (char*)__FUNCTION__, __LINE__ );
			return 0;
		}
	}
	else{
		if( retCode == SQL_NO_DATA )
			return 1;

		if( ( retCode != SQL_SUCCESS ) && ( retCode != SQL_SUCCESS_WITH_INFO ) ){	
			session_->set_error( result_set_->stmt_, sql_, (char*)__FUNCTION__, __LINE__ );
			return 0;
		}		
	}	

	return 1;
}

void ODBC_DBStatement::addBindInfo(unsigned int size, short flag, char* data, \
		short fcType, short sqlType)
{	
	//long int cbParm = (long int)SQL_LEN_DATA_AT_EXEC(size);	
	SQLRETURN retCode = 0;	
	DBTypeTable* table = DBService::Instance()->getTypeTable();

	if( flag == DEF_PARAM_TYPE_INPUT )
		flag = SQL_PARAM_INPUT;
	else if( flag == DEF_PARAM_TYPE_OUTPUT )
		flag = SQL_PARAM_OUTPUT;

	if( table->isODBCString( sqlType ) ){
		retCode = ::SQLBindParameter( result_set_->stmt_, current_bind_pos_, flag, \
			fcType, sqlType, size, 0, data, size, &cbParm_ );
	}
	else{
		retCode = ::SQLBindParameter( result_set_->stmt_, current_bind_pos_, flag, \
			fcType, sqlType, 0, 0, data, 0, &cbParm_ );
	}	
	
	LOG_DEBUG( LOG_SERVICE("instance")->Log("--- %u th---", current_bind_pos_) );	
	LOG_DEBUG( LOG_SERVICE("instance")->Log("data type = %i", fcType) );
	LOG_DEBUG( LOG_SERVICE("instance")->Log("sql type  = %i", sqlType) );
	LOG_DEBUG( LOG_SERVICE("instance")->Log("col size  = %i", size) );
	LOG_DEBUG( LOG_SERVICE("instance")->Log("scale     = %i", 0) );
	LOG_DEBUG( LOG_SERVICE("instance")->Log("size      = %i", size) );	

	if( retCode != SQL_SUCCESS && retCode != SQL_SUCCESS_WITH_INFO ){
		LOG_ERR( LOG_SERVICE("instance")->Log("%s - %u - %u", __FUNCTION__, __LINE__, current_bind_pos_) );
		return;	
	}

	current_bind_pos_++;
}

int ODBC_DBStatement::is_procedure(){
	if( strstr( sql_, "exec" ) )
		return 1;

	if( strstr( sql_, "EXEC" ) )
		return 1;	

	return 0;
}
